/******************************************************************************/
/*  Class LOG                                                                 */
/*  PO: S. Maslyakov, rusoil.9@gmail.com                                      */
/*                                                                            */
/*  Revision:     1.2                                                         */
/*  Date:         2011/03/26 22:28:33                                         */
/******************************************************************************/


#include "data_types.h"
#include "Core\core.h"
#include "Log\log.h"



//==============================================================================
// App: Init Log
//==============================================================================
void LOG::InitLog(const __SETT_HEADER_LOG * const _pSett, const uint32_t _addr) {
    if (m_isLogInit == LOG_FLG_OK_VAL) {
        return;
    };

    if ((_pSett->flash_mem_size == 0)
        || (_addr < MEM_LOG_START_ADDR)
            || (_addr > MEM_LOG_END_ADDR)) {
        return;
    };

    // Allocate flash mem
    AllocMem(_addr, _pSett->flash_mem_size);

    // Set log sett
    m_timePeriod = _pSett->time_period;
    m_recSize = _pSett->rec_size;
    m_cutOff = _pSett->size_cutoff;
    m_isLogInit = LOG_FLG_OK_VAL;

    // Test battery mem
    if (m_pTools->isLogOk != LOG_FLG_OK_VAL) {
        m_pTools->head = 0;
        m_pTools->tile = 0;
        m_pTools->recNum = 0;
        m_pTools->isLogOk = LOG_FLG_OK_VAL;
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Clear Log
//==============================================================================
void LOG::ClearLog() {
    CORE::EnterCriticalSection();

    m_pTools->head = 0;
    m_pTools->tile = 0;
    m_pTools->recNum = 0;

    CORE::ExitCriticalSection();

    EraseMemory();
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get tile
//==============================================================================
uint32_t LOG::GetTile() const {
    return (m_pTools->tile);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get head
//==============================================================================
uint32_t LOG::GetHead() const {
    return (m_pTools->head);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get dotNum
//==============================================================================
uint32_t LOG::GetRecNum() const {
    return (m_pTools->recNum);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Inc tile
//==============================================================================
void LOG::IncTile() {
    CORE::EnterCriticalSection();
    m_pTools->tile = IncLogAddr(m_pTools->tile);
    CORE::ExitCriticalSection();
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Clear dots
//==============================================================================
void LOG::ClearDots(const uint32_t _numDot) {
    const uint32_t qnt = (GetLogSize() > _numDot) ? _numDot : GetLogSize();

    CORE::EnterCriticalSection();
    for (uint32_t i = 0; i < qnt; i++) {
        m_pTools->tile = IncLogAddr(m_pTools->tile);
    };
    CORE::ExitCriticalSection();
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Inc head
//==============================================================================
void LOG::IncHead() {
    CORE::EnterCriticalSection();
    m_pTools->head = IncLogAddr(m_pTools->head);
    CORE::ExitCriticalSection();
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Inc dotNum
//==============================================================================
void LOG::IncRecNum() {
    CORE::EnterCriticalSection();
    m_pTools->recNum++;
    CORE::ExitCriticalSection();
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get log size
//==============================================================================
uint32_t LOG::GetLogSize() const {
    const uint32_t head = m_pTools->head;
    const uint32_t tile = m_pTools->tile;

    return (head >= tile) ? ((head - tile) / GetRecSize())
                  : ((GetMemorySize() - (tile - head)) / GetRecSize());
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Need send log
//==============================================================================
bool_t LOG::NeedSendLog() const {
    const uint32_t busyMem = GetLogSize() * GetRecSize();

    return ((busyMem >= m_cutOff) && (m_cutOff != 0)) ? TRUE_T : FALSE_T;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get free memory
//==============================================================================
uint32_t LOG::GetFreeMemory() const {
    const uint32_t head = m_pTools->head;
    const uint32_t tile = m_pTools->tile;

    return (head >= tile) ? (GetMemorySize() - (head - tile)) : (tile - head);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Test log overflow
//==============================================================================
bool_t LOG::IsLogOverflow() const {
    const uint32_t head = m_pTools->head;
    const uint32_t tile = m_pTools->tile;
    const uint32_t newAddr = IncLogAddr(head);

    if ((head >= tile) && (newAddr > head)) {
        return FALSE_T;
    }
    else {
        return ((newAddr / GetSectorSize()) == (tile / GetSectorSize()))
                                              ? TRUE_T : FALSE_T;
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Inc log addr
//==============================================================================
uint32_t LOG::IncLogAddr(const uint32_t _addr) const {
    // Test at valid addr
    if (_addr >= GetMemorySize()) {
        return _addr;
    };

    const uint32_t newAddr = _addr + GetRecSize();

    return (newAddr < GetMemorySize()) ? newAddr : (newAddr - GetMemorySize());
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Write rec in log
//==============================================================================
uint32_t LOG::WriteRec(const void * const _pData) {
    __FMEM_DATA data;
    uint32_t err = 0;

    // Test error
    if (_pData == 0) {
        return eMEM_ADDR_ERROR;
    };

    // Write header - rec num
    ((__HEADER_LOG *)(_pData))->recNum = m_pTools->recNum;

    // Test at overflow & sector
    while (IsLogOverflow() == TRUE_T) {
        IncTile();
    };

    // Prepare data for write
    data.addr = m_pTools->head;
    data.pBuff = (uint8_t *)_pData;
    data.dataLen = GetRecSize();

    // Write
    if (GetSpaceToEnd(m_pTools->head) < data.dataLen) {
        data.dataLen = GetSpaceToEnd(m_pTools->head);

        err = WriteData(&data);

        data.addr = 0;
        data.pBuff = (uint8_t *)_pData + data.dataLen;
        data.dataLen = GetRecSize() - data.dataLen;
    };

    err |= WriteData(&data);

    if (err == eMEM_OK) {
        // Shift head
        IncRecNum();
        IncHead();
    };

    return err;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Read rec
//==============================================================================
uint32_t LOG::ReadRec(const uint32_t _recNum, uint8_t * const _pDst) {
    __FMEM_DATA data;
    uint32_t err = 0;

    // Test rec num
    if (_recNum >= GetLogSize()) {
        return 0;
    };

    // Prepare data for read
    data.addr = m_pTools->tile;

    for (uint32_t i = 0; i < _recNum; i++) {
        data.addr = IncLogAddr(data.addr);
    };

    data.pBuff = (uint8_t *)_pDst;
    data.dataLen = GetRecSize();

    // Read
    if (GetSpaceToEnd(data.addr) < data.dataLen) {
        data.dataLen = GetSpaceToEnd(data.addr);

        err = ReadData(&data);

        data.addr = 0;
        data.pBuff = (((uint8_t *)_pDst) + data.dataLen);
        data.dataLen = GetRecSize() - data.dataLen;
    };

    err |= ReadData(&data);

    return (err != eMEM_OK) ? 0 : GetRecSize();
}
//==============================================================================
//==============================================================================